/**
 * @Copyright ®2015 Sinosoft Co. Ltd. All rights reserved.<br/>
 * 项目名称 : 中科软支付平台
 * 创建日期 : 2016年12月21日
 * 修改历史 : 
 *     1. [2016年12月21日]创建文件 by liuyujia
 */
package com.sinosoft.sinopay.apiservice.gnetechinapay.service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.springframework.stereotype.Service;

import com.gnete.security.crypt.Crypt;
import com.gnete.security.crypt.CryptException;
import com.sinosoft.sinocloud.platform.base.SinoBaseCheckException;
import com.sinosoft.sinocloud.platform.base.SinoBaseException;
import com.sinosoft.sinocloud.platform.base.SinoBaseService;
import com.sinosoft.sinocloud.platform.common.exception.system.SinoSystemException;
import com.sinosoft.sinocloud.platform.common.util.PropertiesUtil;
import com.sinosoft.sinocloud.platform.common.util.XStreamComponent;
import com.sinosoft.sinopay.api.common.dto.pay.PayInfoReturnDTO;
import com.sinosoft.sinopay.api.pay.dto.InterPayRequestDTO;
import com.sinosoft.sinopay.api.pay.service.InterPayApiService;
import com.sinosoft.sinopay.apiservice.gnetechinapay.dto.GneteChinaPayReqBody;
import com.sinosoft.sinopay.apiservice.gnetechinapay.dto.GneteChinaPayReqInfo;
import com.sinosoft.sinopay.apiservice.gnetechinapay.dto.GneteChinaPayReqTransDetail;
import com.sinosoft.sinopay.apiservice.gnetechinapay.dto.GneteChinaPayReqTransDetails;
import com.sinosoft.sinopay.apiservice.gnetechinapay.dto.GneteChinaPayReqTransSum;
import com.sinosoft.sinopay.apiservice.gnetechinapay.dto.GneteChinaPayReqXml;
import com.sinosoft.sinopay.apiservice.gnetechinapay.dto.GneteChinaPayResBody;
import com.sinosoft.sinopay.apiservice.gnetechinapay.dto.GneteChinaPayResInfo;
import com.sinosoft.sinopay.apiservice.gnetechinapay.dto.GneteChinaPayResTransDetail;
import com.sinosoft.sinopay.apiservice.gnetechinapay.dto.GneteChinaPayResTransDetails;
import com.sinosoft.sinopay.apiservice.gnetechinapay.dto.GneteChinaPayResXml;
import com.sinosoft.sinopay.apiservice.gnetechinapay.util.AmountTransUtil;
import com.sinosoft.sinopay.apiservice.gnetechinapay.util.PropertiesUtils;

/**  
 * 【广银联接口支付实现类】
 * @author liuyujia
 * @date 2016年12月21日 下午3:56:44 
 * @version V1.0  
 */
@Service("InterPayByGnete")
public class GneteChinaPayServiceImpl extends SinoBaseService implements InterPayApiService{

	@Override
	public PayInfoReturnDTO payRequest(InterPayRequestDTO interPayRequestDTO)
			throws SinoBaseException, SinoSystemException {
		// TODO 
		logger.info("广银联支付开始......");
		//记录日志信息
		//定义返回信息
		PayInfoReturnDTO payInfoReturn = new PayInfoReturnDTO();
		try{
			AmountTransUtil amountTransUtil = new AmountTransUtil();
            String Amount = amountTransUtil.transAmount(interPayRequestDTO.getAmount());
			//封装广银联支付请求参数
			GneteChinaPayReqXml  requestXml = new  GneteChinaPayReqXml();
			//请求报文头信息
            GneteChinaPayReqInfo reqHeadInfo = new GneteChinaPayReqInfo();
            //读取配置文件
            String tPath="/config/gneteConfig.properties";
            Properties properties = PropertiesUtils.readProperties(tPath);
            //报文头
            //数据格式
            reqHeadInfo.setDATA_TYPE(properties.getProperty("DATA_TYPE"));
            //处理级别
            reqHeadInfo.setLEVEL(properties.getProperty("LEVEL"));
            //交易流水号
            reqHeadInfo.setREQ_SN(interPayRequestDTO.getPayNo());
            //交易代码
            reqHeadInfo.setTRX_CODE(properties.getProperty("TRX_CODE"));
            //用户名
            reqHeadInfo.setUSER_NAME(properties.getProperty("USER_NAME"));
            //用户密码
            reqHeadInfo.setUSER_PASS(properties.getProperty("USER_PASS"));
            //版本
            reqHeadInfo.setVERSION(properties.getProperty("VERSION"));
            //签名信息
            reqHeadInfo.setSIGNED_MSG("");
            requestXml.setINFO(reqHeadInfo);
            
            //报文体
            GneteChinaPayReqBody reqBody = new GneteChinaPayReqBody();
            //商户信息
            GneteChinaPayReqTransSum reqTransSum = new GneteChinaPayReqTransSum();
            //业务代码  10600-保险费
            reqTransSum.setBUSINESS_CODE("10600");
            //商户代码
            reqTransSum.setMERCHANT_ID(properties.getProperty("MERCHANT_ID"));
            //提交时间
            reqTransSum.setSUBMIT_TIME(interPayRequestDTO.getSubmitTime());
            //总记录数
            reqTransSum.setTOTAL_ITEM(properties.getProperty("TOTAL_ITEM"));
            //总金额
            reqTransSum.setTOTAL_SUM(Amount);
            reqBody.setTRANS_SUM(reqTransSum);
            
            //交易细节信息
            GneteChinaPayReqTransDetails transDetails = new GneteChinaPayReqTransDetails();
            List<GneteChinaPayReqTransDetail> details = new ArrayList<GneteChinaPayReqTransDetail>();
            GneteChinaPayReqTransDetail detail = new GneteChinaPayReqTransDetail();
            //账号名
            detail.setACCOUNT_NAME(interPayRequestDTO.getAccountName());
            //账号
            detail.setACCOUNT_NO(interPayRequestDTO.getAccountNo());
            //账号属性
            detail.setACCOUNT_PROP("0");//0 私人  1 公司
            //账号类型
            detail.setACCOUNT_TYPE(properties.getProperty("ACCOUNT_TYPE"));
            //金额
            detail.setAMOUNT(Amount);
            //银行代码
            detail.setBANK_CODE(interPayRequestDTO.getBankCode());
            //开户行名称
            detail.setBANK_NAME("");
            //开户行所在市
            detail.setCITY("");
            //货币类型
            detail.setCURRENCY(properties.getProperty("CURRENCY"));
            //自定义用户号
            detail.setCUST_USERID("");
            //客户与商户签约并在银联网络备案的客户编号
            detail.setE_USER_CODE("");
            //证件号
            detail.setID("");
            //开户证件类型
            detail.setID_TYPE("");
            //账号属性
            detail.setPROTOCOL_USERID("");
            //协议号
            detail.setPROTOCOL("");
            //开户行所在省
            detail.setPROVINCE("");
            //清算账号
            detail.setRECKON_ACCOUNT("");
            //手机号
            detail.setTEL("");
            //记录序号
            detail.setSN(properties.getProperty("SN"));
            //备注
            detail.setREMARK("");
            //保留域1
            detail.setRESERVE1("");
            //保留域2
            detail.setRESERVE2("");
            //保留域3
            detail.setRESERVE3("");
            //保留域4
            detail.setRESERVE4("");
            //电子联行号
            detail.setELE_BANKNO("");
            //摘要
            detail.setABS("");
            //附言
            detail.setPS("");
            //用途
            detail.setUSE("");
            //信用卡有效期
            detail.setCRE_VAL_DATE("");
            //CVN2码
            detail.setCRE_CVN2("");
            //账号密码
            detail.setACC_PASS("");
            details.add(detail);
            transDetails.setTRANS_DETAILS(details);
            reqBody.setTRANS_DETAILS(transDetails);
            requestXml.setBODY(reqBody);
            
            //调用广银联接口
            //封装请求的xml
            XStreamComponent xstream = new XStreamComponent();
            xstream.processAnnotations(new Class[] { GneteChinaPayReqXml.class,GneteChinaPayReqBody.class,GneteChinaPayReqInfo.class,GneteChinaPayReqTransSum.class, GneteChinaPayReqTransDetails.class,GneteChinaPayReqTransDetail.class,
                    GneteChinaPayResXml.class,GneteChinaPayResBody.class,GneteChinaPayResInfo.class,GneteChinaPayResTransDetails.class,GneteChinaPayResTransDetail.class});
            String reqXml = properties.getProperty("Package_Header")+xstream.toXML(requestXml).replace("__", "_");
            //记录日志信息
            logger.info("广银联支付请求报文:"+reqXml);
            //数据签名
            String signData = this.signMsg(reqXml).replace("__", "_");
            //请求广银联支付
            String strResp = PayRequest(signData);
            //记录日志信息，存储报文
            
            //解析返回报文
            GneteChinaPayResXml response = (GneteChinaPayResXml) xstream.fromXML(strResp);
            //拼接返回参信息
            payInfoReturn.setPayNo(interPayRequestDTO.getPayNo());
            String returnCode = response.getINFO().getRET_CODE();
            
            if(returnCode!=null && !returnCode.equals("0000")){
            	payInfoReturn.setReturnCode("FAIL");
                payInfoReturn.setReturnMsg(response.getINFO().getERR_MSG());
            }
            else{
	            String tAmount = response.getBODY().getRET_DETAILS().getRET_DETAILS().get(0).getAMOUNT();
	            BigDecimal yuanAmount = amountTransUtil.FenToYuan(tAmount);
	            payInfoReturn.setPayAmount(yuanAmount);
	            if(response.getBODY().getRET_DETAILS().getRET_DETAILS().get(0).getRET_CODE()=="0000"){
	            	payInfoReturn.setReturnCode("SUCCESS");
	            }
	            else{
	            	payInfoReturn.setReturnCode(response.getBODY().getRET_DETAILS().getRET_DETAILS().get(0).getRET_CODE());
	            }
	            payInfoReturn.setReturnMsg(response.getBODY().getRET_DETAILS().getRET_DETAILS().get(0).getERR_MSG());
            }
		}
		catch(CryptException ce){
			ce.printStackTrace();
			logger.info("异常信息为:"+ce.getMessage());
			logger.info("",ce);
			logger.error("",ce);
			payInfoReturn.setReturnCode("FAIL");
			payInfoReturn.setReturnMsg(ce.getMessage());
		}
		catch(Exception ex){
			ex.printStackTrace();
			logger.info("异常信息为:"+ex.getMessage());
			logger.info("",ex);
			logger.error("",ex);
			payInfoReturn.setReturnCode("FAIL");
			payInfoReturn.setReturnMsg(ex.getMessage());
		}
		return payInfoReturn;
	}

	/**
	 * 请求广银联支付
	 * @param strSendData
	 * @return
	 */
	private String PayRequest(String strSendData) throws SinoSystemException {
		//请求报文 实时代收
        HttpClient httpClient = new HttpClient( );
        PropertiesUtils propertiesUtils = new PropertiesUtils();
        Properties properties = propertiesUtils.readProperties("/config/gneteConfig.properties");
        PostMethod postMethod =
            new PostMethod(properties.getProperty("SERVER_URL"));
        //设置编码
        httpClient.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET,"GBK");
        //发送的报文
        logger.info("发送广银联报文为："+strSendData);
        postMethod.setRequestBody(strSendData);
        String strResp = null;
        try {
            long start = System.currentTimeMillis();
            //执行getMethod
            int statusCode = httpClient.executeMethod(postMethod);
            logger.info("cost:"+(System.currentTimeMillis()-start));
            //失败
            if (statusCode != HttpStatus.SC_OK) {
                logger.error(
                    "请求失败！Method failed: " + postMethod.getStatusLine());
                //读取内容 
                byte[] responseBody = postMethod.getResponseBody();
                //处理内容
                strResp = new String(responseBody, "GBK");
                logger.error(strResp);              
            }
            else {
                logger.info("SUCCESS......");
                //读取内容 
                byte[] responseBody = postMethod.getResponseBody();
                strResp = new String(responseBody, "GBK");
                logger.info("服务器返回:" + strResp);
                //验签
                if (this.verifySign(strResp)) {
                    logger.info("验签正确，处理服务器返回的报文");
                }
            }
        } catch (HttpException e) {
            //发生致命的异常，可能是协议不对或者返回的内容有问题
            logger.error("协议有误或者返回的内容有问题!", e);
            e.printStackTrace( );
        } catch (IOException e) {
            //发生网络异常
            logger.error("发生网络异常---"+e);
        } catch (Exception e) {
            logger.error("Exception----" +e);
        } finally {
            //释放连接
            postMethod.releaseConnection();
            logger.error("释放连接");
        }
        return strResp;
	}

	/**
	 * 验证签名信息
	 * @param strXML
	 * @return
	 * @throws CryptException
	 */
//	public boolean verifySign(String strXML) throws CryptException {
//        logger.info("验证返回参数签名");
//        //签名(代收付系统JDK环境使用GBK编码，商户使用签名包时需传送GBK编码集)
//        Crypt crypt = new Crypt("gbk" );
//        String rootPath = this.getClass().getResource("/").getPath().toString();
//        String pathCer = rootPath + "config/gzdsf.cer";
//        int iStart = strXML.indexOf("<SIGNED_MSG>");
//        if (iStart != -1) {
//            int end = strXML.indexOf("</SIGNED_MSG>");
//            String signedMsg = strXML.substring(iStart+12, end);
//            logger.info("广银联返回报文验签："+signedMsg);
//            String strMsg = strXML.substring(0, iStart) + strXML.substring(end+13);
//            //调用签名包验签接口(原文,签名,公钥路径)
//            if (crypt.verify(strMsg,signedMsg, pathCer)){
//                logger.info("verify ok");
//                return true;
//            }
//            else {
//                logger.error("verify error");
//                return false;
//            }
//        }
//        return true;
//    }
	private boolean verifySign(String strXML) throws CryptException {
		logger.info("验证返回参数签名");
		//签名(代收付系统JDK环境使用GBK编码，商户使用签名包时需传送GBK编码集)
		Crypt crypt = new Crypt("gbk" );
//		String pathCer = "/usr/local/config/gzdsf.cer";
		String rootPath = this.getClass().getResource("/").getPath().toString();
		String pathCer = rootPath+"config/gzdsf.cer";
		int iStart = strXML.indexOf("<SIGNED_MSG>");
		if (iStart != -1) {
			int end = strXML.indexOf("</SIGNED_MSG>");
			String signedMsg = strXML.substring(iStart+12, end);
			logger.info("广银联返回报文验签："+signedMsg);
			String strMsg = strXML.substring(0, iStart) + strXML.substring(end+13);
			//调用签名包验签接口(原文,签名,公钥路径)
			if (crypt.verify(strMsg,signedMsg, pathCer)){
				logger.info("verify ok");
				return true;
			}
			else {
				logger.error("verify error");
				return false;
			}
		}
		return true;
	}

	/**
	 * 数据签名
	 * @param strData
	 * @return
	 * @throws CryptException
	 */
//	public String signMsg(String strData) throws CryptException {
//        logger.info("-----star---获取数据签名-------");
//        //签名
//        String rootPath = this.getClass().getResource("/").getPath().toString();
//        logger.info("rootPath="+rootPath);
//        Crypt  crypt = new Crypt("gbk");
////        String pathPfx = rootPath+"config"+path()+"ORA@TEST1.pfx";
//        String pathPfx = rootPath+"config/ORA@TEST1.pfx";
//        logger.info("pathPfx:"+pathPfx);
//        String strMsg = strData.replaceAll("<SIGNED_MSG></SIGNED_MSG>", "");
//        //调用签名包签名接口(原文,私钥路径,密码)
//        String signedMsg = crypt.sign(strMsg, pathPfx, "123456");
//        logger.info("签名值为:"+signedMsg);
//        return  strData.replaceAll("<SIGNED_MSG></SIGNED_MSG>", "<SIGNED_MSG>"+signedMsg+"</SIGNED_MSG>");
//    }
	private String signMsg(String strData) throws CryptException {
		logger.info("-----star---获取数据签名-------");
		String strRnt = "";
		//签名(代收付系统JDK环境使用GBK编码，商户使用签名包时需传送GBK编码集)
		Crypt  crypt = new Crypt("gbk");
//		String pathPfx = "/usr/local/config/ORA@TEST1.pfx";
		String rootPath = this.getClass().getResource("/").getPath().toString();
		String pathCer = rootPath+"config/ORA@TEST1.pfx";
		logger.info("pathPfx:"+pathCer);
		String strMsg = strData.replaceAll("<SIGNED_MSG></SIGNED_MSG>", "");
		//调用签名包签名接口(原文,私钥路径,密码)
		String signedMsg = crypt.sign(strMsg, pathCer, "123456");
		logger.info("签名值为:"+signedMsg);
		return  strData.replaceAll("<SIGNED_MSG></SIGNED_MSG>", "<SIGNED_MSG>"+signedMsg+"</SIGNED_MSG>");
	}
	
	/**
	 * 获取绝对路径
	 * @return
	 */
	public String path(){
		return System.getProperty("file.separator");
	}
}
